#include "Usuario.h"
#include "const.h"
#include <syslog.h>
#include "MyException.h"

Usuario::Usuario(std::string n): nombre(n){
}

Usuario::~Usuario(){
	//esperarDesconexion();
}

// Desconecta al usuario. Espera a que se haya desconectado correctamente
// antes de retornar.
void Usuario::esperarDesconexion(){
	this->running = false;
	cola.push(0);
}

// Devuelve el nombre del usuario.
std::string Usuario::obtenerNombre(){
	return this->nombre;
}

void Usuario::run(){
	try {
		std::list<Device*>::const_iterator iterador;

		while(running){
			// Recorre todos los devices conectados y ejecuta las tareas
			// pendientes de cada uno.
			Device * deviceConTarea = cola.pop();
			if ((deviceConTarea == 0)){break;};

			if (deviceConTarea->esperandoDesconexion()) {
				devices.lock();
				desconectarDevice(deviceConTarea);
				devices.unlock();
			} else {
				std::string buff = deviceConTarea->ejecutarTarea(nombre);

				// Si el comando requiere notificar a los demas, lo hace.
				if ((buff.substr(0, buff.find_first_of(" "))) == NOTIFY)
					enviarNotificaciones(buff, deviceConTarea);
			}
		};

		// Cierro todas las conexiones y finalizo el server.
		devices.lock();
		iterador = devices.begin();
		while (iterador != devices.end()){
			iterador = desconectarDevice(*iterador);
		};
		devices.unlock();
	} catch(std::exception& e){
		std::cout << e.what() << std::endl;
		syslog(LOG_ERR, "El programa se ha cerrado inesperadamente: %s ", e.what());
	}
}

// Agrega un nuevo device conectado al cliente.
void Usuario::agregarDevice(Comunicador * c, Comunicador * cn){

	Device * device = new Device(c, cn, cola);
	device->start();
	devices.push_back(device);
}

std::list<Device*>::iterator Usuario::desconectarDevice(Device * device){
	std::list<Device*>::iterator iterador = devices.begin();
	while (iterador != devices.end()){
		if ( (*iterador)->compare(*device) == 0) {
			device->stop();
			device->join();
			delete(device);
			return devices.erase(iterador);
		}
		++iterador;
	};

	throw MyException("Se violo la integridad del modelo: se pidio desconectar un device que no estaba conectado\n");

}

void Usuario::enviarNotificaciones(std::string &notif, Device * device){
	devices.lock();
	std::list<Device*>::const_iterator itAux;
	itAux = devices.begin();
	while (itAux != devices.end()){
		if ((*itAux)->compare((*device)) != 0) (*itAux)->notificar(notif);
		++itAux;
	}
	devices.unlock();
}
